import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:myflutter/config/common.dart';
import 'package:myflutter/config/constant.dart';
import 'package:myflutter/utils/common_widgets.dart';
import 'package:myflutter/utils/json_log_utils.dart';
import 'package:myflutter/utils/log_util.dart';
import 'package:myflutter/utils/sp_util.dart';



class HttpUtil {
  static HttpUtil get instance => _getInstance();
  static HttpUtil? _httpUtil;
  int timeOut = 10000;
  final Map<String,CancelToken> _cancelTokenMap={};

  static HttpUtil _getInstance() {
    _httpUtil ??=  HttpUtil._internal();
    return _httpUtil!;
  }

  //通用全局单例，第一次使用时初始化
  HttpUtil._internal();

  Dio _getDio()  {
    // String? token = SpUtil.instance.getHttpToken();
    String? token = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImM2MTE0MTM3MDE1Yjk3Y2ExZWI2MjU1ODZmZWE0ZjhlMDJlYmVjMDE0MDdlZWE0NGQ0YTk5NTMyOTBiNjg3ODVkN2E0NmU5MmVlZDFmMWMyIn0.eyJhdWQiOiIxNCIsImp0aSI6ImM2MTE0MTM3MDE1Yjk3Y2ExZWI2MjU1ODZmZWE0ZjhlMDJlYmVjMDE0MDdlZWE0NGQ0YTk5NTMyOTBiNjg3ODVkN2E0NmU5MmVlZDFmMWMyIiwiaWF0IjoxNjU3MjU5NDEzLCJuYmYiOjE2NTcyNTk0MTMsImV4cCI6MTY4ODc5NTQxMywic3ViIjoiOCIsInNjb3BlcyI6W10sImlzcyI6Im1lbWJlciJ9.TC2Hh3GWZ2sg8XXlZGEHy5N1ec1dy_v_pGkkwk7eAGvCkWlTlf2ge6OkvNbEAczUwJ-mNsbpJZe1EbGKDtsSHx3w_gRGfsnNfctTc-9MYe60vKm7NdUkgQPzRyMUa4tjPMwUvyQagEShSBKzKJtAyCbd3iWDzspo2J21FRjXpBBca2njwrPQNXeG4vM0_iBSGRQ67AXvO6_ezOTO3TN9NsKFdtQUYTPRWAZkF9MxfCpq3qHHRwOAnuWqMqYLhWXaPvtf_D69GZTxf18B7rPThlO5pohQtVIJT_7K4vCC7MvM3v40-AFfugpJXtjDTxsm4f31TJY8oHoss_OO8riH-Rj-V0RzOO-gTVIC65mEhpzqd-NYPvtT29-hfEmM4quNhOXm8y5n2v4rsJNurlVCqdN4srNIxrE2-YTZ-VbtRVgsfhgr_UcBebUN-xQBvJm1MtB0ZOXoao69BVjASX7zEabN6lURa0lPN9XnwsRSiPWD-VG_xOPWTyRsSMw6xViCBoVzO6gseV9OPKGThCEqHkw0sgz_tNtR41P1VKKpGsSg9uurqlpHEDpZaZbzDGn0Xr58bSJRdmjOdHMwI1tVqHKTaZ_iqjVD0SyPRJgc8qvIaS5TOZr1Q0sXY22oJVZV0RS3ycwMSgMdvzlDbDqheJDFUc3fsru4lClOZWF7yOs";
    Dio _dio = Dio();

    _dio.options
      ..connectTimeout = timeOut
      ..sendTimeout = timeOut
      ..receiveTimeout = timeOut;
    // ..baseUrl = Common.baseApi;
    //日志拦截器
    _dio.interceptors.add(
        InterceptorsWrapper(onRequest: (RequestOptions options,RequestInterceptorHandler handler) {
          //添加请求头token
          // options.headers.addAll({"Authorization":"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ijg0MjIzZTI3ZDZlYTEyYTRlZWMxZDI4ZDEyMWZlOWFkODliODQxNWFmMWZiZDEyNDhjNWFjOWYzMWQ2NWFkMDVhNjRiNmYyZjIxNDU2YjBhIn0.eyJhdWQiOiIzIiwianRpIjoiODQyMjNlMjdkNmVhMTJhNGVlYzFkMjhkMTIxZmU5YWQ4OWI4NDE1YWYxZmJkMTI0OGM1YWM5ZjMxZDY1YWQwNWE2NGI2ZjJmMjE0NTZiMGEiLCJpYXQiOjE2MzQ3MDUzMzQsIm5iZiI6MTYzNDcwNTMzNCwiZXhwIjoxNjY2MjQxMzM0LCJzdWIiOiI4Iiwic2NvcGVzIjpbXSwiaXNzIjoibWVtYmVyIn0.lcUQTTkq7I7Bj1H_33cBBTIwGO5YD1uBUd4usPm90O19rmFoxD1XOoDb-CGbKNb7AcrzTJicqBbOn10XZIUfIwx5x6hSH3CAI5ELZOu1tGbjbJ9zYo02Ston0Bp9kl2UGgDu2YUcDnPXG1-xdtV8tkvITISYVB2qpYEHL-sAj9GrPR6U0Sh5f7PG7KBIhRjcFKHzLEfjPxSw-9OnXixhusXNv_EGrMV7yb_ENM1gyPej2SWlL214a4NVkBIQfrCtCg3pZ77pw_sZ597PWxGqOSpQxor6XAaGUWpwVTHfowvE2eEAyyoFQpSdreMnWRF1wcESZEbtNYT3RE3tIUrBiv2c6kEG_88Li6QAZc4HiJUyYRz9LDIjHeF1vu0K3AIEVIP9S8XuYPo5Basq6AJ06LtOHgV6qPDsJv3l_Abo1h4KX5d6HrgKtaMFfwGkpnR-awffC4E2B-_lG7WrfbtnJioySpp8j8Yv3XEiohYR2kUglcpXTSRgKnZ4K76_1LR0u4cN5TEc4_HAHj5snGkOax4cKlFzKCutYhWqeCv13963BULLBTt4mbBFu5MoDwFFBlYRm9MGpmFnatlkqvCsz6f7a0QoLLmFhBcq5OMsBCP9d4YGzr4EqijO7k_9UIcQAN97_LqSCXw19VuC1MgMeLPMq6KVEQP9motdlsPq9Sc"});
          // options.headers.addAll({"Authorization":'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImFiYWFhOTBmYWY1NTY1OWY5Zjg0NGMxMWY2YTc4MGIxMDk4NThiMzc3NjhiZjEzNjJlNmVhODczOWIxM2UxYWRkNzlmMTk3N2JjNGZhODc5In0.eyJhdWQiOiIzIiwianRpIjoiYWJhYWE5MGZhZjU1NjU5ZjlmODQ0YzExZjZhNzgwYjEwOTg1OGIzNzc2OGJmMTM2MmU2ZWE4NzM5YjEzZTFhZGQ3OWYxOTc3YmM0ZmE4NzkiLCJpYXQiOjE2MzQ2NDQ5OTYsIm5iZiI6MTYzNDY0NDk5NiwiZXhwIjoxNjY2MTgwOTk2LCJzdWIiOiIyMyIsInNjb3BlcyI6W10sImlzcyI6Im1lbWJlciJ9.OK5GEHp9BxJqXgIahaODdwbEffBJijK5n6oZqU6S1X9O3YXPO5ZqXDYJXZeYkgMD70ttoagaK89pghA0zUufyJtCDLsZj_mCy69vPxgRtQYAuYWmW6wsM_6ENpeYwUUduxIrJADWd7ub2Ci6muxaMO1Khq-drM1ytScgLTq20kawFtk4KFlhPIB-dc_ezZYBsGttm0XQn4sJwPeJAuA8JtdCdYxqf69nDmYSyAoo8o9sGUJGHUcLPSa5ELFjFzv69Bf8cOjOok6MyMnwbqy3K5vqXHdquqDkG4NKm_mJkLdcYJkU8ReGxQ5GEBGeJ2NW2XCmUMMFLaZZfYpDaE1jPyCUJpNrVEoqM8NFWZiMI43RDonnXsJBh2YcPhB2F-nguo293ebbk2tipT2y32uIFbTNmrsY7xTZsVOn6AH26ta-KHGoeW6DjsDsIIe3-pAlV-hC9D7Wu7iM1TMT_NQP9btX4qGlQl8pgasm-GyFuwjjRLekh98nNU_aq7ZrcDOVlPqXNnJ-WqPo7eb5ZC4LMCn3BTNwgwM6ibCfriJRbn8Ikqrm5wIA7hyA3L3P8WTR_vVxMRj9ZPVc5QhIIg-EyUGrKIMDUoWrNWCzrQmwLvf-rwwDH9_TZXNZwLO99LsW89SG98i7ZufZzTn1_kgnJIm005Wkqo9T0az_x0b_7EY'});
          // options.headers.addAll({"R":"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjY5YmMxMjI5NDBlYzdhNGQ1ODE3YWUxNmZjNmIyYTFiYTEwMjI1MDQ3N2E5MGMxMDZiODRhYmQwN2IzMjdjZDkxMjcyZDVkNjY0ZDc2YzRjIn0.eyJhdWQiOiI1IiwianRpIjoiNjliYzEyMjk0MGVjN2E0ZDU4MTdhZTE2ZmM2YjJhMWJhMTAyMjUwNDc3YTkwYzEwNmI4NGFiZDA3YjMyN2NkOTEyNzJkNWQ2NjRkNzZjNGMiLCJpYXQiOjE2Mzk3MTI5MTMsIm5iZiI6MTYzOTcxMjkxMywiZXhwIjoxNjcxMjQ4OTEzLCJzdWIiOiIzNzMiLCJzY29wZXMiOltdLCJpc3MiOiJtZW1iZXIifQ.lDDM0v33ztBBgYZ5WIvfaO6jmuO7SJ3A72Ld39lgfDhkB1ABEwsNZx1BdKzwXgp2EsZCEVQIwU7gZP9TZoZB41dhOlbfDihvvxbfX5zcThoRYGcj84OZmyvJFpB-rf6wwtZI_JnMllJKSx-dtl0Qo6GxAIR9TLhOWHgixVHFSNkgC7QKVuRf1A9EHoQ7ALC6F1ZKN4Dy1VD6aTAZQCqsFDEfm4m6uTfpHlWbhnMLh218lboy2JXiPzZJN7QkYvqC8jmaMjr_Z6ZHhnBueiohHVuH1u7cB20bpWHCGZ1J0L03GZZnJAcNVvqEMGMxBHQZWQSfiJ8D5HTEAAp1bPE_PhjVcXHqpP0o82uyjOU4E2HOX8_Km2e0HmJqmnwGI0Mrf-SeZQ75EmFfTpzyYAM2viOIHhUHq48Ekk3foYxHNt21hDKLF-eIXWw60s3CLxWq6Ui4C_Wa-sR2lX1sxPj6XP7gpvmZ32gmcZhwOFLsHNjF6xaAzcCDNXzx53zzC9EosxfFBnZhStagFk7lq-6om7QtXx4XLnqNVYlGmg6H2PvJvxMmh6VEDhQfDBCs6qBU2n8ffGapCydZfB62lqvSx3WEiTlWPca8zbJVN96ylV8_0ZHEGspmjMfjXBjYRVKPs7jkjTZbW8_ez93rEm680mqILP5wUhtA0QPq4YWcqrE"});

          options.headers.addAll({"Authorization": token});
      // print("\n================================= 请求数据 =================================");
      LogUtil.d("method = ${options.method.toString()}");
      LogUtil.d("url = ${options.uri.toString()}");
      LogUtil.d("headers = ${options.headers}");
      LogUtil.d("params = ${options.queryParameters}");
      LogUtil.d("data = ${options.data}");
      return handler.next(options);
    }, onResponse: (Response response,ResponseInterceptorHandler handler) {
          LogUtil.d(
          "\n================================= 响应数据开始 =================================");
      LogUtil.d("code = ${response.statusCode}");
      LogUtil.d("data = ${response.data}");
      LogUtil.d(
          "format_data = ${JsonLogUtils.convert(response.data, 0, isObject: true)}");
      LogUtil.d(
          "================================= 响应数据结束 =================================\n");
      return handler.next(response);
    }, onError: (DioError e,ErrorInterceptorHandler errorHandler) {
          LogUtil.d(
          "\n=================================错误响应数据 =================================");
      LogUtil.d("type = ${e.type}");
      LogUtil.d("message = ${e.message}");
      LogUtil.d("response = ${e.response}");
      LogUtil.d("error = ${e.error}");
      LogUtil.d("\n");
      return errorHandler.next(e);
    }));
    _dio.options.headers['Authorization'] = token;
    if(!Common.isRelease){///只在debug模式下运行
      //配置抓包代理
      (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) {
        if(Constant.proxyUrl.length>0){
          client.findProxy = (uri) {
            //proxy all request to localhost:8888
            print('PROXY '+Constant.proxyUrl+':'+Constant.proxyPort);
            return 'PROXY '+Constant.proxyUrl+':'+Constant.proxyPort; //测试电脑代理ip
            // return "PROXY 192.168.10.28:8866";
          };
          // 你也可以自己创建一个新的HttpClient实例返回。
          // return new HttpClient(SecurityContext);
          //抓Https包设置
          client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
        }else{
          client.findProxy=null;
          client.badCertificateCallback = null;
        }
      };
    }
    return _dio;
  }

  //通用的POST请求
  Future<Response> post(api, {Map<String, dynamic>? parameters, Map<String, dynamic>? data, Options? options,
    bool showLoading = false,BuildContext? context}) async {
    assert(!showLoading||context!=null);
    String tmpApi=api;
    String? baseApi=SpUtil.instance.getBaseApi();
    if(baseApi == null || baseApi.isEmpty){
      baseApi=Common.DEFAULT_API;
    }
    api=baseApi+api;
    if (showLoading) {
      CommonWidgets.showLoadingWidgets(context!);
    }
    Response response;
    CancelToken _cancelToken = CancelToken();
    _cancelTokenMap[tmpApi]=_cancelToken;
    try {
      response = await _getDio().post(api, queryParameters: parameters, data: data, options: options,cancelToken: _cancelToken);
      if (showLoading) {
        CommonWidgets.dismissLoading();
      }
      _cancelTokenMap.remove(tmpApi);
      return response;
    } on DioError catch (e) {
      if (showLoading) {
        CommonWidgets.dismissLoading();
      }
      _cancelTokenMap.remove(tmpApi);
      if(e.type==DioErrorType.cancel){//取消请求
        Fluttertoast.cancel();
        return  Response(data: {'code': 'CANCEL','message':null}, requestOptions: _cancelToken.requestOptions!);
      }
      if(e.type==DioErrorType.connectTimeout){
        // Fluttertoast.showToast(msg: '请求超时');
        return  Response(data: {'code': 'TIME_OUT','message':'请求超时'}, requestOptions: _cancelToken.requestOptions!);
      }

      //处理请求返回的鉴权失败
      if (e.response != null && e.response!.statusCode == 401) {
        // LoginUtil.instance.loginNativePage();
        print("无效Token");
      } else if (e.response != null && e.response!.statusCode == 500) {
        String message = '服务器错误';
        return  Response(
            statusCode: 500,data: {'code':'error','message':message}, requestOptions: _cancelToken.requestOptions!);
      }else if (e.response != null && e.response!.statusCode == 422) {
        String message = '未知错误';
        Map <dynamic, dynamic>arg = e.response!.data['data'];
        arg.forEach((key, value) {
          if(arg.values.length > 0){
            if(arg.values.first.length>0){
              message  = arg.values.first[arg.values.first.length>1?1:0];
            }
          }
        });
        print('message=== ${message.toString()}');
        return  Response(
          statusCode: 422,data: {'code':'error','message':message}, requestOptions: _cancelToken.requestOptions!);
      }
      return e.response != null ? e.response! : Response(statusCode: 666, data: {'code': 'no_response'}, requestOptions: _cancelToken.requestOptions!);
    }
  }

  Future<Response> get(api, {Map<String,
      dynamic>? parameters, Options? options, bool showLoading = false,BuildContext? context}) async {
    assert(!showLoading||context!=null);
    String tmpApi=api;
    String? baseApi=SpUtil.instance.getBaseApi();
    if(baseApi == null || baseApi.isEmpty){
      baseApi=Common.DEFAULT_API;
    }
    api=baseApi+api;
    if (showLoading) {
      CommonWidgets.showLoadingWidgets(context!);
    }
    CancelToken _cancelToken =  CancelToken();
    _cancelTokenMap[tmpApi]=_cancelToken;
    try {
      Response response = await _getDio().get(api, queryParameters: parameters, options: options,cancelToken: _cancelToken);
      if (showLoading) {
        CommonWidgets.dismissLoading();
      }
      _cancelTokenMap.remove(tmpApi);
      return response;
    } on DioError catch (e) {
      if (showLoading) {
        CommonWidgets.dismissLoading();
      }
      _cancelTokenMap.remove(tmpApi);
      if(e.type==DioErrorType.cancel){//取消请求
        Fluttertoast.cancel();
        return  Response(data: {'code': 'CANCEL','message':null}, requestOptions: _cancelToken.requestOptions!);
      }
      if(e.type==DioErrorType.connectTimeout){
        // Fluttertoast.showToast(msg: '请求超时');
        return  Response(data: {'code': 'TIME_OUT','message':'请求超时'}, requestOptions: _cancelToken.requestOptions!);
      }
      //处理请求返回的鉴权失败
      if (e.response != null && e.response!.statusCode == 401) {
        // LoginUtil.instance.loginNativePage();
        print("无效Token");

      } else if (e.response != null && e.response!.statusCode == 500) {
        String message = '服务器错误';
        return  Response(statusCode: 500,data: {'code':'error','message':message}, requestOptions: _cancelToken.requestOptions!);
      }else if (e.response != null && e.response!.statusCode == 422) {
        String message = '未知错误';
        Map <dynamic, dynamic>arg = e.response!.data['data'];
        arg.forEach((key, value) {
          if(arg.values.length > 0){
            message  = arg.values.first[0];
          };
        });
        print('message=== ${message.toString()}');
        return Response(statusCode: 422,data: {'code':'error','message':message}, requestOptions: _cancelToken.requestOptions!);
      }
      return e.response != null ? e.response! : Response(statusCode: 666, data: {'code': 'no_response'}, requestOptions: _cancelToken.requestOptions!);
    }
  }

  void cancel(String cancelApi){
    if(!_cancelTokenMap.containsKey(cancelApi)){
      return;
    }
    CancelToken? cancelToken=_cancelTokenMap[cancelApi];
    if(cancelToken!=null&&!cancelToken.isCancelled){
      _cancelTokenMap.remove(cancelApi);
      cancelToken.cancel('$cancelApi is cancelled');
    }
  }

  void dispose(){
    _cancelTokenMap.clear();
  }

  // 下载
  static Future<Response> download(String url, String savePath,
      Function(int count, int total) progressCallback) async {
    return Dio().download(url, savePath, onReceiveProgress: progressCallback);
  }
}